package sample;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

import java.awt.*;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.List;

import org.apache.poi.POIXMLDocument;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;
import org.jsoup.Connection;
import org.jsoup.Jsoup;

public class Main extends Application {

    private Button openButton = new Button("选择文件");
    private Text ftext = new Text(12, 12, "0%");
    private Text mtext = new Text(12,12,"请先将要翻译的文件修改为docx类型文件后,选择文件即可。\r\n翻译完成后的文件将保存在被翻译文件同目录下\r\nwyne1986,QQ366659539");
    private double fnum = 0.01;

    @Override
    public void start(final Stage stage) throws IOException {
        stage.setTitle("文件翻译");
        stage.setResizable(false);

        final FileChooser fileChooser = new FileChooser();

        openButton.setMinWidth(80);
        openButton.setMaxWidth(80);
        openButton.setOnAction(
                (final ActionEvent e) -> {
                    configureFileChooser(fileChooser);
                    File file = fileChooser.showOpenDialog(stage);
                    if (file != null) {
                        openFile(file);
                    }
                });

        final GridPane inputGridPane = new GridPane();

        GridPane.setConstraints(openButton, 0, 0);
        GridPane.setConstraints(ftext, 1, 0);
        GridPane.setConstraints(mtext, 0, 1);
        GridPane.setColumnSpan(mtext, 2);
        inputGridPane.setHgap(140);
        inputGridPane.setVgap(30);
        inputGridPane.getChildren().addAll(openButton,ftext,mtext);

        final Pane rootGroup = new VBox(140);
        rootGroup.getChildren().addAll(inputGridPane);
        rootGroup.setPadding(new Insets(12, 12, 12, 12));

        stage.setTitle("文件翻译");
        stage.setScene(new Scene(rootGroup));
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

    private static void configureFileChooser(final FileChooser fileChooser){
        fileChooser.setTitle("文件翻译");
        fileChooser.setInitialDirectory(
                new File(System.getProperty("user.home"))
        );
    }

    private void openFile(File file) {
        EventQueue.invokeLater(() -> {
            ftext.setText(fnum+"%");
            translateDoc(file.getAbsolutePath());
            ftext.setText("完成");
        });
    }

    private static OPCPackage opcPackage;
    private static XWPFDocument document;

    public void translateDoc(String path) {
        try {
            if (path.endsWith(".docx")) {
                opcPackage = POIXMLDocument.openPackage(path);
                document = new XWPFDocument(opcPackage);
                List<IBodyElement> elements = document.getBodyElements();
                int p = 0;
                for (IBodyElement element : elements) {
                    if (element instanceof XWPFParagraph) {
                        //段落元素处理
                        replaceDocxText((XWPFParagraph)element);
                    }else if (element instanceof XWPFTable) {
                        //表格元素处理
                        List<XWPFTableRow> rows = ((XWPFTable)element).getRows();
                        for (XWPFTableRow row : rows) {
                            List<XWPFTableCell> cells = row.getTableCells();
                            for (XWPFTableCell cell : cells) {
                                List<XWPFParagraph> paragraphs = cell.getParagraphs();
                                for (XWPFParagraph paragraph : paragraphs) {
                                    replaceDocxText(paragraph);
                                }
                            }
                        }
                    }
                    p++;
                    fnum = Math.floor(p/(double)elements.size()*10000)/100;
                    ftext.setText(fnum+"%");
                }
                FileOutputStream outStream = new FileOutputStream(path+".docx");
                document.write(outStream);
                outStream.close();
                opcPackage.close();
            } else {
                ftext.setText("不是docx文件");
            }
        } catch(Exception e){
            e.printStackTrace();
        }
    }

    private static void replaceDocxText(XWPFParagraph paragraph){
        List<XWPFRun> runs = paragraph.getRuns();
        for (int i = 0; i < runs.size(); i++) {
            String oneparaString = runs.get(i).getText(runs.get(i).getTextPosition());
            if(oneparaString==null || oneparaString.trim().isEmpty() || oneparaString.trim().length()<3 || !oneparaString.trim().matches("^.*[a-zA-Z]+.*$")) continue;
            oneparaString = oneparaString.trim().replaceAll("(.*)[\\]\\},\"\\):]$","$1");
            while(true){
                JSONObject gobj = google(oneparaString);
                if(gobj==null || gobj.getInteger("status")!=0)continue;
                oneparaString = oneparaString.replace(oneparaString, gobj.getString("data"));
                break;
            }
            runs.get(i).setText(oneparaString, 0);
        }
    }

    private static Map<String,String> GoogleHeaders = new HashMap<String,String>(){{
        put("user-agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36");
    }};

    private static Map<String,String> GoogleCookies = new HashMap<String,String>();

    public static Map initGoogle(){
        try{
            Connection.Response res = Jsoup.connect("https://translate.google.cn").headers(GoogleHeaders).execute();
            GoogleCookies = res.cookies();
        }catch (Exception e){
            e.printStackTrace();
        }
        return GoogleCookies;
    }

    public static JSONObject google(String text){
        JSONObject json = new JSONObject(){{
            put("text",text);
        }};
        return google(json);
    }

    public static JSONObject google(String text,String to){
        JSONObject json = new JSONObject(){{
            put("to",to);put("text",text);
        }};
        return google(json);
    }

    public static JSONObject google(String text,String to,String from){
        JSONObject json = new JSONObject(){{
            put("from",from);put("to",to);put("text",text);
        }};
        return google(json);
    }

    public static JSONObject google(JSONObject json){
        JSONObject resjson = new JSONObject();
        if(GoogleCookies.isEmpty()) initGoogle();
        String from = json.getString("from");
        String to = json.getString("to");
        String text = json.getString("text");
        if(from==null || from.isEmpty()){
            from = "auto";
        }
        if(to==null || to.isEmpty()){
            to = "zh-CN";
        }
        if(text==null || text.isEmpty()){
            resjson.put("status",401);
            resjson.put("message","缺少参数text");
            return resjson;
        }
        try{
            String data = URLEncoder.encode("[[[\"MkEWBc\",\"[[\\\""+text+"\\\",\\\""+from+"\\\",\\\""+to+"\\\",true],[null]]\",null,\"generic\"]]]","UTF-8");
            Connection.Response res = Jsoup.connect("https://translate.google.cn/_/TranslateWebserverUi/data/batchexecute")
                    .method(Connection.Method.POST).headers(GoogleHeaders).cookies(GoogleCookies).requestBody("f.req="+data)
                    .maxBodySize(0).ignoreContentType(true).execute();
            if(res==null) return null;
            String resstr = res.body();
            String[] resarr = resstr.split("\n");
            if(resarr.length<3){
                resjson.put("status",405);
                resjson.put("message","google response failed");
                return resjson;
            }
            String re = resarr[2].trim().replaceAll("(\\\\\\n)","");
            if(re==null||re.isEmpty()){
                resjson.put("status",406);
                resjson.put("message","google response failed");
                return resjson;
            }
            String jsonstr = JSONArray.parseArray(JSONArray.parseArray(re).getString(0)).getString(2);
            jsonstr.replaceAll("\\\\\"","\"");
            JSONArray rarr = JSONArray.parseArray(jsonstr).getJSONArray(1).getJSONArray(0).getJSONArray(0);
            if(rarr==null||rarr.isEmpty()){
                resjson.put("status",407);
                resjson.put("message","google response failed");
                return resjson;
            }
            String py = rarr.getString(1);
            String fn = rarr.getJSONArray(5).getJSONArray(0).getString(0);
            if(fn==null||fn.isEmpty()){
                resjson.put("status",408);
                resjson.put("message","google response failed");
                return resjson;
            }
            resjson.put("status",0);
            resjson.put("message","ok");
            resjson.put("data",fn);
            return resjson;
        }catch (Exception e){
            resjson.put("status",409);
            resjson.put("message","translate failed:"+e.toString());
            return resjson;
        }
    }
}
